#include <iostream>
#include <sstream>
#include <assert.h>
#include "DDEventManager.hh"
#include "DDVData.hh"
#include "DDVAnalysis.hh"
#include "TEveElement.h"
#include "TH1.h"
#include "TCanvas.h"
#include "TROOT.h"

ClassImp( DDEventManager );

DDEventManager::DDEventManager() {

  loadedDataClasses.clear();
  loadedDataClasses.clear();
  loadedDataClasses.clear();

  m_EventID=-1;
}
DDEventManager::~DDEventManager() {}


void DDEventManager::RegisterDataClass( DDVData* data, std::string name ) {
  loadedDataClasses[name] = data;
  std::cout << "DDEventManager::RegisterDataClass: Registered " << name << " " << data << std::endl;
}

void DDEventManager::RegisterAnalysisClass( DDVAnalysis* analysis, std::string name ) {
  loadedAnalysisClasses[name] = analysis;
  AnalysesOrder.push_back( name );
  std::cout << "DDEventManager::RegisterAnalysisClass: Registered " << name << " " << analysis << std::endl;
}


void DDEventManager::Initialize( TEveManager* eveMan ) {

  m_eveManager = eveMan;

  std::cout << "================================" << std::endl;


  // Initialize Data Classes
  std::map< std::string, DDVData* >::iterator it;
  for ( it = loadedDataClasses.begin(); it!=loadedDataClasses.end(); it++) {
    if ( (*it).second==NULL) {
      std::cout << "  Data Class " << (*it).first << " is NULL!" << std::endl;
      assert( false );
    }
	cout << (*it).first << endl;
    int err = (*it).second->Initialize();


    if (err!=DDEventManager::kOK) {
      std::cout << "Error in initializing data class " << (*it).first << std::endl;
      assert(false);
    }
  }

/*
  // Initialize Visual Analysis Classes
  std::map< std::string, DDVAnalysis* >::iterator it;
  for ( it = loadedDataClasses.begin(); it!=loadedDataClasses.end(); it++) {
    if ( (*it).second==NULL) {
      std::cout << "  Analysis Pointer to " << (*it).first << " is NULL!" << std::endl;
      assert( false );
    }
    int err = (*it).second->Initialize( this );
    if (err!=DDEventManager::kOK) {
      std::cout << "Error in initializing data class " << (*it).first << std::endl;
      assert(false);
    }
    std::cout << "Initialized Analysis Class " << (*it).first << std::endl;
//    if ( (*it).second->HasDigiDataToDisplay() == true ) {
  //    loadedDigiSets[ (*it).first ] = (*it).second->GetDigiData();
   //   eveMan->AddElement( (*it).second->GetDigiData() );
    //  std::cout << "Registered Analysis Class DigitSet of " << (*it).first << std::endl;
   // }
  }
*/  
  std::cout << "================================" << std::endl;

  MakeEventNavGui( eveMan );
}

void DDEventManager::TearDownData() {
  std::map< std::string, DDVData* >::iterator it;
  for ( it = loadedDataClasses.begin(); it!=loadedDataClasses.end(); it++) {
    if ( (*it).second!=NULL) {
      (*it).second->TearDown();
    }
  }
}

void DDEventManager::RunAnalyses() {
  // Initialize  Analysis Classes
  int err;
  std::map< std::string, DDVData* >::iterator dataclass;
  std::map< std::string, DDVAnalysis* >::iterator analysisclass;
  for ( analysisclass = loadedAnalysisClasses.begin(); analysisclass!=loadedAnalysisClasses.end(); analysisclass++) {
    for ( dataclass = loadedDataClasses.begin(); dataclass!=loadedDataClasses.end(); dataclass++) {	  
	 cout << "CALLING GET CHANNELS FROM EVENTMANAGER" << endl;
	 ((*dataclass).second)->get_header()->get_channels();
	 cout << "DONE CALLING GET CHANNELS FROM EVENTMANAGER" << endl;
     err = (*analysisclass).second->Analyze((*dataclass).second);
	}
	DisplayAnalyses();
    if (err!=DDEventManager::kOK) {
      std::cout << "Error in initializing analysis class " << (*analysisclass).first << std::endl;
      assert(false);
    }
  }
  
}

  
void DDEventManager::DisplayEvents() {
  //Draw histograms from all channels of all data classes
  //to their respective TCanvases

  //Draw data histograms
  std::map<string, DDVData*>::iterator it; 
  std::map<int, TH1F*> channels;
  std::map<int, TH1F*>::iterator channel_it;
	
  stringstream channel_number;
  string canvas_name;

  for ( it = loadedDataClasses.begin(); it!=loadedDataClasses.end(); ++it) {

    channels = (it->second)->GetCurrentTrace();

    for ( channel_it = channels.begin(); channel_it!=channels.end(); ++channel_it) {
	    canvas_name = it->first;
		channel_number << channel_it->first;
		canvas_name += channel_number.str();

		canvases[canvas_name]->cd(0); //Change active canvas (Is this effective?)
		channel_it->second->Draw(); //Draw the histogram
		canvases[canvas_name]->Update(); //Refresh the canvas
		
		channel_number.str("");
		canvas_name="";

    }
  }
}
	
void DDEventManager::DisplayAnalyses() {
  //Draw analysis histograms
  std::map<string, DDVAnalysis*>::iterator it; 
  std::map<int, TH1F*> channels;
  std::map<int, TH1F*>::iterator channel_it;
	
  stringstream channel_number;
  string canvas_name;

  float bincont;

  for ( it = loadedAnalysisClasses.begin(); it!=loadedAnalysisClasses.end(); ++it) {

    channels = *((it->second)->GetHistos());

    for ( channel_it = channels.begin(); channel_it!=channels.end(); ++channel_it) {

	    canvas_name = it->first;
		channel_number << channel_it->first;
		canvas_name += channel_number.str();

		cout << canvas_name << endl;

		cout << "AROO" << endl;

		canvases[canvas_name]->cd(0); //Change active canvas (Is this effective?)
		channel_it->second->Draw(); //Draw the histogram
		canvases[canvas_name]->Update(); //Refresh the canvas

		bincont = channel_it->second->GetBinContent(1);
		cout << "BIN1CONT: " << bincont << endl;
		
		channel_number.str("");
		canvas_name="";

    }
  }
}

void DDEventManager::GoToEvent(int n) {
  
  
  std::map< std::string, DDVData* >::iterator it;
  for ( it = loadedDataClasses.begin(); it!=loadedDataClasses.end(); it++) {
    int err = (*it).second->GoToEvent(n);
    if (err!=DDEventManager::kOK) {
      std::cout << "Error in loading data class " << (*it).first << std::endl;
      assert(false);
    }
		DisplayEvents();
  }
  m_EventID = n;
  std::cout << "Redraw" << std::endl;
  std::map< std::string, TEveElement* >::iterator it_digi;
  for ( it_digi = loadedDigiSets.begin(); it_digi!=loadedDigiSets.end(); it_digi++) {
    std::cout << " " << (*it_digi).first << std::endl;
    m_eveManager->ElementChanged( (*it_digi).second, kTRUE, kTRUE);
  }


  std::cout << "draw3d" << std::endl;
  m_eveManager->Redraw3D( kFALSE, kTRUE );

}

#include "TEveBrowser.h"
#include "TRootBrowser.h"
#include "TGFrame.h"
#include "TGClient.h"
#include "TString.h"
#include "TGButton.h"

void DDEventManager::MakeEventNavGui(  TEveManager* eveMan ) {

  // Stolen from the Eve Root Tutorials. Thanks!
  
  TEveBrowser* browser = eveMan->GetBrowser();
  browser->StartEmbedding(TRootBrowser::kLeft);

  TGMainFrame* frmMain = new TGMainFrame(gClient->GetRoot(), 1000, 600);
  frmMain->SetWindowName("XX GUI");
  frmMain->SetCleanup(kDeepCleanup);

  TGHorizontalFrame* hf = new TGHorizontalFrame(frmMain);
  {
    TString icondir("./");
    TGPictureButton* b = 0;
    
    b = new TGPictureButton(hf, gClient->GetPicture(icondir+"GoBack.gif"));
    hf->AddFrame(b);
    b->Connect("Clicked()", "DDEventManager", this, "GetPrevEvent()");
   
    b = new TGPictureButton(hf, gClient->GetPicture(icondir+"GoForward.gif"));
    hf->AddFrame(b);
    b->Connect("Clicked()", "DDEventManager", this, "GetNextEvent()");

    b = new TGPictureButton(hf, gClient->GetPicture(icondir+"integral.gif"));
    hf->AddFrame(b);
    b->Connect("Clicked()", "DDEventManager", this, "RunAnalyses()");
  }
  frmMain->AddFrame(hf);
 
  frmMain->MapSubwindows();
  frmMain->Resize();
  frmMain->MapWindow();
 
  browser->StopEmbedding();

  //Create Canvas tabs for all channels of all Data and corresponding analysis classes

  std::map<string, DDVData*>::iterator data_it;
  std::map<string, DDVAnalysis*>::iterator analysis_it;
	std::set<int>::iterator channel_it;	

  stringstream channel_number;
  string canvas_name;

  for ( data_it = loadedDataClasses.begin(); data_it!=loadedDataClasses.end(); ++data_it) 
	{
				
		for ( channel_it = (*((data_it->second)->get_header()->get_channels())).begin(); channel_it!=(*((data_it->second)->get_header()->get_channels())).end(); ++channel_it) 
		{
		  canvas_name = data_it->first;
		  channel_number << *(channel_it);
		  canvas_name+=channel_number.str();
			browser->StartEmbedding(1, -1);
			canvases.insert(pair<string,TCanvas*>(canvas_name, new TCanvas)); 
			cout << canvas_name << endl;
			browser->StopEmbedding(canvas_name.c_str());
			channel_number.str(std::string()); // Clear stream
		  canvas_name=""; // Clear string
	
		  for ( analysis_it = loadedAnalysisClasses.begin(); analysis_it!=loadedAnalysisClasses.end(); ++analysis_it) 
			{
			  canvas_name = analysis_it->first;
			  channel_number << *(channel_it);
			  canvas_name+=channel_number.str();
				browser->StartEmbedding(1, -1);
				canvases.insert(pair<string,TCanvas*>(canvas_name, new TCanvas)); 
				browser->StopEmbedding(canvas_name.c_str());
				channel_number.str(std::string()); // Clear stream
			  canvas_name=""; // Clear string
		  }
	  }

		browser->SetTabTitle("Event Control", 0);
	}			

}	
void DDEventManager::GetNextEvent() { 

	cout << m_EventID << endl;
  m_EventID++;
  std::cout << "Called Next Event " <<  m_EventID << std::endl;
  GoToEvent( m_EventID ); 
};

void DDEventManager::GetPrevEvent() { 
  m_EventID--;
  std::cout << "Called Prev Event " << m_EventID << std::endl;
  GoToEvent( m_EventID ); 
};
